package org.jaaksi.recorddemo;

import android.media.AudioFormat;
import android.media.AudioRecord;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class MainActivity extends AppCompatActivity implements AudioRecorder.AudioRecordCallback {
  private static final String TAG = "MainActivity";

  private AudioRecorder mAudioRecorder = new AudioRecorder();
  private File mPcmFile;
  private int mSampleRate = 8000;
  private int mPcmDataFormat = AudioFormat.ENCODING_PCM_16BIT;
  private int mChannels = 1;
  private FileOutputStream mFileOutputStream;
  private boolean mIsRecording = false;
  AudioMessageRecord record = new AudioMessageRecord();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    record.setChannels(1);
    record.setOutFilePath("/sdcard/abc/audio.wav");

    mPcmFile = new File(Utils.getAudioOutputPcm());
    mAudioRecorder.setSampleRate(mSampleRate);
    mAudioRecorder.setPcmFormat(mPcmDataFormat);
    mAudioRecorder.setChannels(mChannels);
    mAudioRecorder.setRecordCallback(this);
  }

  public void onClick(View view) {
    //startRecord();
    record.startRecord();
  }

  public void onStop(View view) {
    //stopRecord();
    record.stopRecord();
  }

  private void startRecord() {
    if (mAudioRecorder.start()) {
      try {
        mFileOutputStream = new FileOutputStream(mPcmFile);
      } catch (FileNotFoundException e) {
        e.printStackTrace();
      }
      mIsRecording = true;
    }
  }

  private void stopRecord() {
    mIsRecording = false;
    mAudioRecorder.stop();
    try {
      mFileOutputStream.flush();
      mFileOutputStream.close();
    } catch (IOException e) {
      Log.e(TAG, "onRecordEnded exception occur: " + e.getMessage());
    }
    pcmToWav(mPcmFile, new File(Utils.getAudioOutputWav()));
  }

  private void pcmToWav(File pcmFile, File wavFile) {
    FileInputStream fis = null;
    FileOutputStream fos = null;
    try {
      fis = new FileInputStream(pcmFile);
      fos = new FileOutputStream(wavFile);

      int sampleFormat = mPcmDataFormat == AudioFormat.ENCODING_PCM_16BIT ? 16 : 8;
      writeWavHeader(fos, fis.getChannel().size(), sampleFormat, mSampleRate, mChannels);

      int channelConfig =
        mChannels == 1 ? AudioFormat.CHANNEL_IN_MONO : AudioFormat.CHANNEL_IN_STEREO;
      int bufferSize = AudioRecord.getMinBufferSize(mSampleRate, channelConfig, mPcmDataFormat);

      byte[] data = new byte[bufferSize];
      while (fis.read(data) != -1) {
        fos.write(data);
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      try {
        if (fis != null) {
          fis.close();
        }

        if (fos != null) {
          fos.flush();
          fos.close();
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }

  /**
   * 表1　8KHz采样、16比特量化的线性PCM语音信号的WAVE文件头格式表（共44字节）
   * 偏移地址 字节数 数据类型 内容 文件头定义为
   * 00H 4 char "RIFF" char riff_id[4]="RIFF"
   * 04H 4 long int 文件总长-8 long int size0=文总长-8
   * 08H 8 char "WAVEfmt " char wave_fmt[8]
   * 10H 4 long int 10 00 00 00H(PCM) long int size1=0x10
   * 14H 2 int 01 00H int fmttag=0x01
   * 16H 2 int int channel=1 或2
   * 18H 4 long int 采样率 long int samplespersec
   * 1CH 4 long int 每秒播放字节数 long int bytepersec
   * 20H 2 int 采样一次占字节数 int blockalign=声道数*量化数/8
   * 22H 2 int 量化数 int bitpersamples=8或16
   * 24H 4 char "data" char data_id="data"
   * 28H 4 long int 采样数据字节数 long int size2=文长-44
   * 2CH 到文尾 char 采样数据 　
   * @param fos
   * @param pcmDataLength
   * @param sampleFormat
   * @param sampleRate
   * @param channels
   * @throws IOException
   */
  private void writeWavHeader(@NonNull FileOutputStream fos, long pcmDataLength, int sampleFormat,
    int sampleRate, int channels) throws IOException {
    long totalLen = pcmDataLength + 36; // 44 - 8
    long bitRate = sampleRate * channels * sampleFormat / 8; // 32000
    byte[] header = new byte[44];
    // RIFF
    header[0] = 'R';
    header[1] = 'I';
    header[2] = 'F';
    header[3] = 'F';
    // 文件总长度 - 8
    header[4] = (byte) (totalLen & 0xff);
    header[5] = (byte) ((totalLen >> 8) & 0xff);
    header[6] = (byte) ((totalLen >> 16) & 0xff);
    header[7] = (byte) ((totalLen >> 24) & 0xff);
    // WAVE
    header[8] = 'W';
    header[9] = 'A';
    header[10] = 'V';
    header[11] = 'E';
    // 'fmt '
    header[12] = 'f';
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16;
    header[17] = 0;
    header[18] = 0;
    header[19] = 0;
    // 1(PCM)
    header[20] = 1;
    header[21] = 0;
    // channels
    header[22] = (byte) channels; // 2
    header[23] = 0;
    // sample rate
    header[24] = (byte) (sampleRate & 0xff);
    header[25] = (byte) ((sampleRate >> 8) & 0xff);
    header[26] = (byte) ((sampleRate >> 16) & 0xff);
    header[27] = (byte) ((sampleRate >> 24) & 0xff);
    // bit rate
    header[28] = (byte) (bitRate & 0xff);
    header[29] = (byte) ((bitRate >> 8) & 0xff);
    header[30] = (byte) ((bitRate >> 16) & 0xff);
    header[31] = (byte) ((bitRate >> 24) & 0xff);
    header[32] = 4;
    header[33] = 0;
    // 采样精度
    header[34] = (byte) sampleFormat; // 16
    header[35] = 0;
    // data
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    // 语音数据的长度 length
    header[40] = (byte) (pcmDataLength & 0xff);
    header[41] = (byte) ((pcmDataLength >> 8) & 0xff);
    header[42] = (byte) ((pcmDataLength >> 16) & 0xff);
    header[43] = (byte) ((pcmDataLength >> 24) & 0xff);
    fos.write(header);
  }

  @Override public void onRecordSample(byte[] data) {
    if (mIsRecording) {
      try {
        mFileOutputStream.write(data);
      } catch (IOException e) {
        Log.e(TAG, "onRecordSample write data failed: " + e.getMessage());
      }
    }
  }
}
